#ifndef _MEM_BUFFER_H_
#define _MEM_BUFFER_H_

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

	typedef const struct
	{
		void* (*add)(const void* mem, int len);
		void* (*align_add)(const void* mem, int len, int align);
		void* (*insert)(int pos, const void* mem, int len);
		void* (*remove)(int pos, int len);
		void* (*add_str)(const char* str);
		void* (*add_str_nz)(const char* str);
	} mem_buf_api_type;

	typedef struct
	{
		uint8_t* mem;
		int len_now;
		int len_max;
		int len_limit;
		mem_buf_api_type* api;
	} mem_mbuf_type;

	int mem_mbuf_init(mem_mbuf_type* obj, int len_limit, int len_init);

	int mem_mbuf_free(mem_mbuf_type* obj);

	void* mem_mbuf_add(mem_mbuf_type* obj, const void* mem, int len);

	void* mem_mbuf_align_add(mem_mbuf_type* obj, const void* mem, int len, int align);

	void* mem_mbuf_insert(mem_mbuf_type* obj, int pos, const void* mem, int len);

	void* mem_mbuf_remove(mem_mbuf_type* obj, int pos, int len);

	void* mem_mbuf_add_str(mem_mbuf_type* membuf, const char* str);
	void* mem_mbuf_add_str_nz(mem_mbuf_type* membuf, const char* str);

	typedef struct
	{
		uint8_t* mem;
		int len_now;
		int len_max;
		mem_buf_api_type* api;
	} mem_fbuf_type;

	void mem_fbuf_init(mem_fbuf_type* obj, void* mem, int len_max);
	void* mem_fbuf_add(mem_fbuf_type* obj, const void* mem, int len);
	void* mem_fbuf_align_add(mem_fbuf_type* obj, const void* mem, int len, int align);
	void* mem_fbuf_insert(mem_fbuf_type* obj, int pos, const void* mem, int len);
	void* mem_fbuf_remove(mem_fbuf_type* obj, int pos, int len);
	void* mem_fbuf_add_str(mem_fbuf_type* membuf, const char* str);
	void* mem_fbuf_add_str_nz(mem_fbuf_type* membuf, const char* str);

#define mem_buf_api_link(obj, name) obj.api = &name

#define mem_buf_api_make(obj, type, name)                              \
	static void *name##_add(const void *mem, int len)                  \
	{                                                                  \
		return mem_##type##_add(&obj, mem, len);                       \
	}                                                                  \
	static void *name##_align_add(const void *mem, int len, int align) \
	{                                                                  \
		return mem_##type##_align_add(&obj, mem, len, align);          \
	}                                                                  \
	static void *name##_insert(int pos, const void *mem, int len)      \
	{                                                                  \
		return mem_##type##_insert(&obj, pos, mem, len);               \
	}                                                                  \
	static void *name##_remove(int pos, int len)                       \
	{                                                                  \
		return mem_##type##_remove(&obj, pos, len);                    \
	}                                                                  \
	static void *name##_add_str(const char *str)                       \
	{                                                                  \
		return mem_##type##_add_str(&obj, str);                        \
	}                                                                  \
	static void *name##_add_str_nz(const char *str)                    \
	{                                                                  \
		return mem_##type##_add_str_nz(&obj, str);                     \
	}                                                                  \
	mem_buf_api_type name = {                                          \
		name##_add,                                              \
		name##_align_add,                                        \
		name##_insert,                                           \
		name##_remove,                                           \
		name##_add_str,                                          \
		name##_add_str_nz,                                       \
	}

#define mem_buf_offset(buf, p) ((size_t)(p) - (size_t)(buf))

#ifdef __cplusplus
}
#endif

#endif 
